home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
snprintf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
17KB
|
771 lines
#include "config.h"
#ifndef HAVE_SNPRINTF
#include <ctype.h>
#include <sys/types.h>
/* Define this as a fall through, HAVE_STDARG_H is probably already set */
#define HAVE_VARARGS_H
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long (blong@fiction.net) 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long (blong@fiction.net) 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
**************************************************************/
/* varargs declarations: */
#if defined(HAVE_STDARG_H)
# include <stdarg.h>
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
# define VA_LOCAL_DECL va_list ap
# define VA_START(f) va_start(ap, f)
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
# define VA_END va_end(ap)
#else
# if defined(HAVE_VARARGS_H)
# include <varargs.h>
# undef HAVE_STDARGS
# define VA_LOCAL_DECL va_list ap
# define VA_START(f) va_start(ap) /* f is ignored! */
# define VA_SHIFT(v,t) v = va_arg(ap,t)
# define VA_END va_end(ap)
# else
/*XX ** NO VARARGS ** XX*/
# endif
#endif
int snprintf (char *str, size_t count, const char *fmt, ...);
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
static void dopr (char *buffer, size_t maxlen, const char *format,
va_list args);
static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags);
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
long double fvalue, int min, int max, int flags);
static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
{
str[0] = 0;
dopr(str, count, fmt, args);
return(strlen(str));
}
/* VARARGS3 */
#ifdef HAVE_STDARGS
int snprintf (char *str,size_t count,const char *fmt,...)
#else
int snprintf (va_alist) va_dcl
#endif
{
#ifndef HAVE_STDARGS
char *str;
size_t count;
char *fmt;
#endif
VA_LOCAL_DECL;
VA_START (fmt);
VA_SHIFT (str, char *);
VA_SHIFT (count, size_t );
VA_SHIFT (fmt, char *);
(void) vsnprintf(str, count, fmt, ap);
VA_END;
return(strlen(str));
}
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
#define DP_F_MINUS 1
#define DP_F_PLUS 2
#define DP_F_SPACE 4
#define DP_F_NUM 8
#define DP_F_ZERO 16
#define DP_F_UP 32
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define char_to_int(p) (p - '0')
#define MAX(p,q) ((p >= q) ? p : q)
static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
{
char ch;
long value;
long double fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
state = DP_S_DEFAULT;
currlen = flags = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE)
{
if ((ch == '\0') || (currlen >= maxlen))
state = DP_S_DONE;
switch(state)
{
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
dopr_outch (buffer, &currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch)
{
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit(ch))
{
min = 10*min + char_to_int (ch);
ch = *format++;
}
else if (ch == '*')
{
min = va_arg (args, int);
ch = *format++;
state = DP_S_DOT;
}
else
state = DP_S_DOT;
break;
case DP_S_DOT:
if (ch == '.')
{
state = DP_S_MAX;
ch = *format++;
}
else
state = DP_S_MOD;
break;
case DP_S_MAX:
if (isdigit(ch))
{
if (max < 0)
max = 0;
max = 10*max + char_to_int (ch);
ch = *format++;
}
else if (ch == '*')
{
max = va_arg (args, int);
ch = *format++;
state = DP_S_MOD;
}
else
state = DP_S_MOD;
break;
case DP_S_MOD:
/* Currently, we don't support Long Long, bummer */
switch (ch)
{
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'l':
cflags = DP_C_LONG;
ch = *format++;
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch)
{
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
value = va_arg (args, short int);
else if (cflags == DP_C_LONG)
value = va_arg (args, long int);
else
value = va_arg (args, int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'o':
flags &= ~DP_F_PLUS;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned short int);
else if (cflags == DP_C_LONG)
value = va_arg (args, unsigned long int);
else
value = va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
break;
case 'u':
flags &= ~DP_F_PLUS;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned short int);
else if (cflags == DP_C_LONG)
value = va_arg (args, unsigned long int);
else
value = va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
break;
case 'X':
flags |= DP_F_UP;
case 'x':
flags &= ~DP_F_PLUS;
if (cflags == DP_C_SHORT)
value = va_arg (args, unsigned short int);
else if (cflags == DP_C_LONG)
value = va_arg (args, unsigned long int);
else
value = va_arg (args, unsigned int);
fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, long double);
else
fvalue = va_arg (args, double);
/* um, floating point? */
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, long double);
else
fvalue = va_arg (args, double);
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg (args, long double);
else
fvalue = va_arg (args, double);
break;
case 'c':
dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
break;